package com.dynamicthreadpool.spi;

import com.dynamicthreadpool.spi.annotation.Adaptive;
import com.dynamicthreadpool.spi.compiler.AdaptiveCompiler;
import com.dynamicthreadpool.spi.compiler.Compiler;
import com.dynamicthreadpool.spi.extension.SPI;

import java.io.*;
import java.lang.reflect.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 扩展加载器
 * 从Dubbo 2.7版本提取的完整实现
 */
public class ExtensionLoader<T> {

    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
    private static final String COMMA_SEPARATOR = ",";
    private static final String SEMICOLON_SEPARATOR = ";";
    private static final String HASH_SIGN = "#";
    private static final String EQUAL_SIGN = "=";

    private static final Map<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
    private static final Map<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();

    private final Class<?> type;
    private final ClassLoader classLoader;
    private final Map<String, String> cachedNames = new ConcurrentHashMap<>();
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
    private final Map<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
    private volatile Class<?> cachedAdaptiveClass = null;
    private String cachedDefaultName = null;
    private final CopyOnWriteArrayList<Class<?>> cachedWrapperClasses = new CopyOnWriteArrayList<>();
    private volatile Throwable createAdaptiveInstanceError = null;

    private ExtensionLoader(Class<?> type) {
        this.type = type;
        this.classLoader = findClassLoader();
    }

    /**
     * 获取指定类型的扩展加载器
     */
    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type must be interface");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type without @SPI annotation: " + type.getName());
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

    /**
     * 检查是否有@SPI注解
     */
    private static boolean withExtensionAnnotation(Class<?> type) {
        return type.isAnnotationPresent(SPI.class);
    }

    /**
     * 查找类加载器
     */
    private ClassLoader findClassLoader() {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            cl = getClass().getClassLoader();
        }
        if (cl == null) {
            cl = ClassLoader.getSystemClassLoader();
        }
        return cl;
    }

    /**
     * 获取指定名称的扩展实例
     */
    @SuppressWarnings("unchecked")
    public T getExtension(String name) {
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }

        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

    /**
     * 获取默认扩展实例
     */
    @SuppressWarnings("unchecked")
    public T getDefaultExtension() {
        getExtensionClasses();
        if (cachedDefaultName == null || cachedDefaultName.isEmpty() || "true".equals(cachedDefaultName)) {
            return null;
        }
        return getExtension(cachedDefaultName);
    }

    /**
     * 获取自适应扩展实例
     */
    @SuppressWarnings("unchecked")
    public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.getMessage(), createAdaptiveInstanceError);
            }

            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.getMessage(), t);
                    }
                }
            }
        }

        return (T) instance;
    }

    /**
     * 创建自适应扩展
     */
    @SuppressWarnings("unchecked")
    private T createAdaptiveExtension() {
        try {
            return (T) getAdaptiveExtensionClass().newInstance();
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

    /**
     * 获取自适应扩展类
     */
    private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

    /**
     * 创建自适应扩展类
     */
    private Class<?> createAdaptiveExtensionClass() {
        try {
            String code = createAdaptiveExtensionClassCode();
            ClassLoader classLoader = findClassLoader();
            Compiler compiler = AdaptiveCompiler.class.newInstance();
            return compiler.compile(code, classLoader);
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException("Can't create adaptive extension class", e);
        }
    }

    /**
     * 创建自适应扩展类代码
     */
    private String createAdaptiveExtensionClassCode() {
        StringBuilder codeBuilder = new StringBuilder();
        codeBuilder.append("package ").append(type.getPackage().getName()).append("\n\n");
        codeBuilder.append("public class ").append(type.getSimpleName()).append("$Adaptive implements ").append(type.getName()).append(" {\n\n");
        
        // 遍历所有方法
        for (Method method : type.getMethods()) {
            // 只处理带有@Adaptive注解的方法
            if (!method.isAnnotationPresent(Adaptive.class)) {
                codeBuilder.append("    public ").append(method.getReturnType().getName())
                        .append(" ").append(method.getName()).append("(");
                // 构建方法参数
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    codeBuilder.append(parameterTypes[i].getName()).append(" arg").append(i);
                    if (i < parameterTypes.length - 1) {
                        codeBuilder.append(", ");
                    }
                }
                codeBuilder.append(") {\n");
                codeBuilder.append("        throw new UnsupportedOperationException(\"The method \" + \").append(method.getName())")
                        .append(" + \" of interface \" + \").append(type.getName())")
                        .append(" + \" is not adaptive method\");\n");
                codeBuilder.append("    }\n\n");
                continue;
            }

            // 处理带有@Adaptive注解的方法
            Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
            String[] keys = adaptiveAnnotation.value();
            if (keys.length == 0) {
                // 如果没有指定key，使用接口名的点分隔小驼峰形式
                keys = new String[]{type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1)};
            }

            // 构建方法签名
            codeBuilder.append("    public ").append(method.getReturnType().getName())
                    .append(" ").append(method.getName()).append("(");
            Class<?>[] parameterTypes = method.getParameterTypes();
            String[] parameterNames = new String[parameterTypes.length];
            for (int i = 0; i < parameterTypes.length; i++) {
                parameterNames[i] = "arg" + i;
                codeBuilder.append(parameterTypes[i].getName()).append(" ").append(parameterNames[i]);
                if (i < parameterTypes.length - 1) {
                    codeBuilder.append(", ");
                }
            }
            codeBuilder.append(") {\n");

            // 查找URL参数
            int urlIndex = -1;
            for (int i = 0; i < parameterTypes.length; i++) {
                if (parameterTypes[i].getName().equals("com.dynamicthreadpool.spi.URL")) {
                    urlIndex = i;
                    break;
                }
            }

            if (urlIndex != -1) {
                // URL参数存在
                codeBuilder.append("        if (arg").append(urlIndex).append(" == null) {\n");
                codeBuilder.append("            throw new IllegalArgumentException(\"url == null\");\n");
                codeBuilder.append("        }\n");
                codeBuilder.append("        com.dynamicthreadpool.spi.URL url = arg").append(urlIndex).append(";\n");
            } else {
                // URL参数不存在，需要从其他参数中获取
                codeBuilder.append("        com.dynamicthreadpool.spi.URL url = null;\n");
                codeBuilder.append("        for (int i = 0; i < args.length; i++) {\n");
                codeBuilder.append("            if (args[i] instanceof com.dynamicthreadpool.spi.URL) {\n");
                codeBuilder.append("                url = (com.dynamicthreadpool.spi.URL) args[i];\n");
                codeBuilder.append("                break;\n");
                codeBuilder.append("            }\n");
                codeBuilder.append("        }\n");
                codeBuilder.append("        if (url == null) {\n");
                codeBuilder.append("            throw new IllegalArgumentException(\"Failed to get url from method parameters\");\n");
                codeBuilder.append("        }\n");
            }

            // 获取扩展名称
            codeBuilder.append("        String extName = null;\n");
            for (int i = 0; i < keys.length; i++) {
                codeBuilder.append("        if (extName == null) {\n");
                codeBuilder.append("            extName = url.getParameter(\"").append(keys[i]).append(", \"");
                if (i == keys.length - 1) {
                    codeBuilder.append(", \"").append(cachedDefaultName).append("\"");
                }
                codeBuilder.append(");\n");
                codeBuilder.append("        }\n");
            }

            codeBuilder.append("        if (extName == null) {\n");
            codeBuilder.append("            throw new IllegalStateException(\"Fail to get extension \" + \").append(type.getName())")
                    .append(" + \" name from url(\" + url + \")\");\n");
            codeBuilder.append("        }\n");

            // 获取扩展实例
            codeBuilder.append("        com.dynamicthreadpool.spi.ExtensionLoader extensionLoader = com.dynamicthreadpool.spi.ExtensionLoader.getExtensionLoader(")
                    .append(type.getName()).append(".class);\n");
            codeBuilder.append("        Object extension = extensionLoader.getExtension(extName);\n");

            // 调用目标方法
            codeBuilder.append("        return ((").append(type.getName()).append(") extension).").append(method.getName()).append("(");
            for (int i = 0; i < parameterNames.length; i++) {
                codeBuilder.append(parameterNames[i]);
                if (i < parameterNames.length - 1) {
                    codeBuilder.append(", ");
                }
            }
            codeBuilder.append(");\n");
            codeBuilder.append("    }\n\n");
        }

        codeBuilder.append("}");
        return codeBuilder.toString();
    }

    /**
     * 创建扩展实例
     */
    @SuppressWarnings("unchecked")
    private T createExtension(String name) {
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw new IllegalStateException("No such extension " + type.getName() + " by name " + name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type.getName() + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

    /**
     * 获取扩展类Map
     */
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

    /**
     * 加载扩展类
     */
    private Map<String, Class<?>> loadExtensionClasses() {
        // 获取默认扩展名称
        SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if (value != null && !value.isEmpty()) {
                cachedDefaultName = value;
            }
        }

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // 加载META-INF/services/下的配置文件
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        // 加载META-INF/dubbo/下的配置文件
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        // 加载META-INF/dubbo/internal/下的配置文件
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        return extensionClasses;
    }

    /**
     * 加载指定目录下的配置文件
     */
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        String fileName = dir + type.getName();
        try {
            Enumeration<URL> urls;
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    loadResource(extensionClasses, classLoader, url);
                }
            }
        } catch (Throwable t) {
            // 忽略异常
        }
    }

    /**
     * 加载资源文件
     */
    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, URL url) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 处理注释
                int commentIndex = line.indexOf(HASH_SIGN);
                if (commentIndex >= 0) {
                    line = line.substring(0, commentIndex);
                }
                line = line.trim();
                if (line.length() > 0) {
                    try {
                        int index = line.indexOf(EQUAL_SIGN);
                        String name = index > 0 ? line.substring(0, index).trim() : line;
                        String clazzName = index > 0 ? line.substring(index + 1).trim() : null;
                        if (name.length() > 0 && clazzName != null && clazzName.length() > 0) {
                            // 加载并缓存扩展类
                            loadClass(extensionClasses, classLoader, name, clazzName);
                        }
                    } catch (Throwable t) {
                        // 忽略异常
                    }
                }
            }
        } catch (IOException e) {
            // 忽略异常
        }
    }

    /**
     * 加载扩展类
     */
    private void loadClass(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, String name, String clazzName) throws ClassNotFoundException {
        Class<?> clazz = classLoader.loadClass(clazzName);
        // 检查是否实现了目标接口
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error when load extension class(" + clazzName + "): class not subtype of " + type.getName());
        }
        // 检查是否有@Adaptive注解
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            }
        } else if (isWrapperClass(clazz)) {
            // 检查是否是包装类
            cachedWrapperClasses.add(clazz);
        } else {
            try {
                // 普通扩展类 - 检查是否有无参构造函数
                clazz.getConstructor();
                extensionClasses.put(name, clazz);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("Error when load extension class (" + clazzName + "): no default constructor", e);
            }
        }
    }

    /**
     * 检查是否是包装类
     */
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * 获取所有支持的扩展名称
     */
    public Set<String> getSupportedExtensions() {
        Map<String, Class<?>> classes = getExtensionClasses();
        return new HashSet<>(classes.keySet());
    }

    /**
     * 持有值的类
     */
    private static class Holder<T> {
        private volatile T value;

        public T get() {
            return value;
        }

        public void set(T value) {
            this.value = value;
        }
    }
}
